package com.colmmcsky.ljreader;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import com.colmmcsky.ljreader.R;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;

public class LjReader extends Activity {

	private int mContentCount;
	private Vector<String> mContents;
	private Vector<String> mTimestamps;
	private StringBuffer mProgressbuffer;
	private Extractor mExtractor;

	private class Extractor extends Thread {
		private String mUser;
		private String mPassword;
		public Extractor(String user, String password) {
			mUser = user;
			mPassword = password;
		}
		
		private void sendMessage(String string) {
	        Message message = Message.obtain();			
	        message.obj = string;
	        mOutputUpdater.sendMessage(message);	
		}
		
		public void run() {
			Vector<String> urls = new Vector<String>();
	    	try {
	    		sendMessage("Loggin in...");
	    		
	    		// set up http client
		    	HttpClient httpClient = new DefaultHttpClient();
		    	HttpContext localContext = new BasicHttpContext();
		    	
		    	// Login
		        HttpPost httppost = new HttpPost("http://www.livejournal.com/login.bml"); 
		        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);  
		        nameValuePairs.add(new BasicNameValuePair("mode", "login"));  
		        nameValuePairs.add(new BasicNameValuePair("user", mUser));  
		        nameValuePairs.add(new BasicNameValuePair("password", mPassword));  
		        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));  
		        httpClient.execute(httppost);  
			
		        sendMessage("Getting Entry list...");
					
		    	HttpGet httpGet = new HttpGet("http://www.livejournal.com/mobile/friends.bml");
				HttpResponse response = httpClient.execute(httpGet, localContext);
				HttpEntity entity = response.getEntity();

				String page = new String(EntityUtils.toByteArray(entity));
				
				// get each "link" link to build the list of entries
				int linkstart = page.indexOf("<a href=", 0);
				int linktag = page.indexOf(">", linkstart);
				int linkend = page.indexOf("</a>", linktag);
				while (linkstart > 0 && urls.size() < 20) {
					String linkpath = page.substring(linkstart+9, linktag-1);
					String linktext = page.substring(linktag+1, linkend);
					
					if (linkpath.endsWith("?format=light")) {
						//if (!linkpath.startsWith("http://community")) {
							urls.add(linkpath);
						//}
					}
					
					linkstart = page.indexOf("<a href=", linkend);
					linktag = page.indexOf(">", linkstart);
					linkend = page.indexOf("</a>", linktag);
				}		
					
				// get the content of each entry
				mProgressbuffer = new StringBuffer();
				mTimestamps = new Vector<String>();
				mContents = new Vector<String>();
				mContentCount = urls.size();
				for (String url : urls){
					ContentGetter getter = new ContentGetter(httpClient, localContext, url);
					getter.run(); // for now, run this synchronously																
				}
				
				// When each content has been gotten, ContentHandler will sort and display them
			} 
	    	catch (Exception e) {
				e.printStackTrace();
				sendMessage("Exception: " + e.getLocalizedMessage());	
			} 			
		}
	}

	// Get each page in parallel
	private class ContentGetter extends Thread {
		private HttpClient mClient;
		private HttpContext mContext;
		private String mUrl;
		public ContentGetter(HttpClient client, HttpContext context, String url) {
			mClient = client;
			mContext = context;
			mUrl = url;
		}
		
		public void run() {
			String page = "fail";
			try {
		    	HttpGet httpGet = new HttpGet(mUrl);
				HttpResponse response = mClient.execute(httpGet, mContext);
				HttpEntity entity = response.getEntity();
				page = new String(EntityUtils.toByteArray(entity));
			} 
			catch (Exception e) {
				e.printStackTrace();
				page = "Exception: " + e.getLocalizedMessage();
			}

	        Message message = Message.obtain();			
	        message.obj = page;
	        mContentHandler.sendMessage(message);	
		}
	}

	// handle incoming contents
	private class ContentHandler extends Handler {
		
		public boolean mActive = true;

		private void sendMessage(String string) {
	        Message message = Message.obtain();			
	        message.obj = string;
	        if (mActive) {
	        	mOutputUpdater.sendMessage(message);
	        }
		}

		private String sortPages(Vector<String> contents,
				Vector<String> timestamps) {
			StringBuffer buffer = new StringBuffer();

			// add the first content to the page
			buffer.append(contents.elementAt(0));
			
			// remove first content from the vectors, we don't want to sort it with the others
			contents.remove(0);
			timestamps.remove(0);
			
			while (contents.size() > 0) {
				// find the highest timestamp
				int maxindex = 0;
				String stamp = timestamps.elementAt(0);
				for (int i=0; i<timestamps.size(); ++i){
					if (stamp.compareTo(timestamps.elementAt(i)) < 0) {
						stamp = timestamps.elementAt(i);
						maxindex = i;
					}
				}
				
				// add the latest content to the page
				buffer.append("<big><big><center>---" + timestamps.elementAt(maxindex) + "---</center></big></big>");
				buffer.append(contents.elementAt(maxindex));
				
				// remove that content from the vectors
				contents.remove(maxindex);
				timestamps.remove(maxindex);
			}
			return buffer.toString();
		}

		private String getTimeStamp(String content, boolean community) {
			// find the fifth link
			int linkstart = 0;
			for (int i=0; i< (community ? 7 : 5); ++i) {
				linkstart = content.indexOf("<a href=", linkstart+1);
			}

			// get the part after livejounal.com
			int datestart = content.indexOf("livejournal.com", linkstart) + 16;
			datestart = content.indexOf("/", datestart+1)+1;
			if (community) {
				datestart = content.indexOf("/", datestart+1)+1;
			}
			int dateend = content.indexOf("/\">", datestart);
			
			// get the time immediately following
			int timestart = content.indexOf("</a>", dateend)+4;
			int timeend = content.indexOf("</font>", timestart);
			
			// put it all together
			String timestamp = content.substring(datestart, dateend) + content.substring(timestart, timeend);
			timestamp = timestamp.replaceAll("/", "-");
			timestamp = timestamp.substring(0, timestamp.length()-3);
			
			// find the timestamps for each comment
			int stampstart = content.indexOf("<br /><font size='-1'>");
			while (stampstart >= 0) {	
				stampstart += 22;				
				if (content.charAt(stampstart) != '@'){	
					int stampend = content.indexOf(" (local)", stampstart);
					if (stampend > 0) {
						String stamp = content.substring(stampstart,stampend);
						if ((stamp.endsWith("pm") || stamp.endsWith("pm")) 
								&& stamp.substring(11,13).equals("12")) {
							stamp = stamp.substring(0, 11)
										+ "00"
										+ stamp.substring(13);
						}
						if (stamp.endsWith("pm")) {
							stamp = stamp.substring(0, 11)
										+ (Integer.parseInt(stamp.substring(11,13)) + 12)
										+ stamp.substring(13);
						}
						stamp = stamp.substring(0, 16);
						
						// if the comment stamp is the newest so far, make it the new timestamp
						if (timestamp.compareTo(stamp) < 0) {
							timestamp = stamp;
						}
					}
				}
				stampstart = content.indexOf("<br /><font size='-1'>", stampstart+1);
			}
			return timestamp;
		}	
		
		public void handleMessage(Message message) {
			String page = (String) message.obj;

			int contentstart = page.indexOf("<body ");
			contentstart = page.indexOf(">", contentstart)+1;
			int contentend = page.indexOf("<p>[ <a href='http://www.livejournal.com/'>Home</a> |");
						
			if (contentstart < 0 || contentend < 0) {		
				// 404ed?
				sendMessage(page);
				return;
			}	
				
			String content = page.substring(contentstart, contentend);
			mContents.add(content);
			String timestamp = getTimeStamp(content, page.contains("<a href='http://community.livejournal.com/"));
			mTimestamps.add(timestamp);
					
			// start by showing the first gotten page
			if (mProgressbuffer.length() == 0) {
				mProgressbuffer.append(content);	
			}
			
			// count down to when all pages have been gotten
			mProgressbuffer.append(mContentCount - mContents.size() + ".");
			
			sendMessage(mProgressbuffer.toString());
			
			// show all pages, sorted (except first gotten first)
			if (mContents.size() == mContentCount) {
				String all = sortPages(mContents, mTimestamps);
				try {
					FileOutputStream fOut = openFileOutput("cache.html", MODE_PRIVATE);
					OutputStreamWriter osw = new OutputStreamWriter(fOut); 
					osw.write(all);
		            osw.flush(); 
		            osw.close();
		            
					sendMessage(all);	
				} catch (FileNotFoundException e) {
					page = "Could not write cache file: " + e.getLocalizedMessage();
					sendMessage(page);	
				} catch (IOException e) {
					page = "Could not write cache file: " + e.getLocalizedMessage();
					sendMessage(page);	
				}
			}
		}
	}
	
	private ContentHandler mContentHandler;
	
	// Update the output when the extraction is done
	private class OutputUpdater extends Handler {
		private WebView mOutput;
		public OutputUpdater(WebView output) {
			mOutput = output;
		}
		
		public void handleMessage(Message message) {
			String text = (String) message.obj;
			mOutput.loadDataWithBaseURL("http://www.livejournal.com/", text, "text/html", "utf-8", "http://www.livejournal.com/");
			//mOutput.setText(text);
		}
	}
	
	private OutputUpdater mOutputUpdater;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        WebView output = (WebView)findViewById(R.id.webview);
    	mOutputUpdater = new OutputUpdater(output);    
		output.loadDataWithBaseURL("http://www.livejournal.com/", "Loading from cache...", "text/html", "utf-8", "http://www.livejournal.com/");
    	
    	try {
    		FileInputStream fIn = openFileInput("cache.html"); 
    		InputStreamReader isr = new InputStreamReader(fIn); 
    		/* Prepare a char-Array that will 
    		 * hold the chars we read back in. */ 
    		char[] inputBuffer = new char[fIn.available()]; 
    		// Fill the Buffer with data from the file 
    		isr.read(inputBuffer); 
    		// Transform the chars to a String 
    		String readString = new String(inputBuffer); 

			output.loadDataWithBaseURL("http://www.livejournal.com/", "Cache:<br>" + readString, "text/html", "utf-8", "http://www.livejournal.com/");
    	} catch (IOException e) { 
			String err = "Could not read cache file: " + e.getLocalizedMessage();
			output.loadDataWithBaseURL("http://www.livejournal.com/", err, "text/html", "utf-8", "http://www.livejournal.com/");
    	}
    }

    /** create the menu items */
    public void populateMenu(Menu menu) {
    	menu.add("Reload");
    }
    
    /** hook into menu button for activity */
    @Override public boolean onCreateOptionsMenu(Menu menu) {
    	populateMenu(menu);
    	return super.onCreateOptionsMenu(menu);
    }

    /** when menu button option selected */
    @Override public boolean onOptionsItemSelected(MenuItem item) {
    	return applyMenuChoice(item) || super.onOptionsItemSelected(item);
    }
    /** respond to menu item selection */
    public boolean applyMenuChoice(MenuItem item) {
    	// Stop previous loading
    	if (mContentHandler != null) {
    		mContentHandler.mActive = false;
    	}
    	
    	// Start new loading
    	mContentHandler = new ContentHandler();
    	mExtractor = new Extractor("username", "password");
    	mExtractor.start();	  
    	return true;
    }
}
